#include <QWebPage>
#include <QWebFrame>
#include <QWebElement>
#include <QDebug>
#include <QTextEdit>
#include <QDir>

#include <gumbo.h>
#include <windows.h>

#include "brandpageparser.h"
#include "constants.h"
#include "imagedownloader.h"
#include "databasemanager.h"
#include "modelpageparser.h"

namespace Jcr
{

class BrandPageParserPrivate
{
public:
    QList<QUrl> modelDetailPages;
    QMap<std::string, std::vector<std::string> > brandModelsMap;
    StdStringMap modelLinkMap;
    int calledTimes = 0;
    std::string previousKey;

    void searchForImageLinks(GumboNode* node);
    void searchForLinksEx(GumboNode* node, const char* name);
    void searchForLinks(GumboNode* node);
    void searchForBrandModels(GumboNode* node);
    void searchForModels(GumboNode* node, std::vector<std::string>& models);
};

void BrandPageParserPrivate::searchForImageLinks(GumboNode* node)
{
    if (node->type != GUMBO_NODE_ELEMENT)
        return;

    GumboAttribute* attr = nullptr;
    if (node->v.element.tag == GUMBO_TAG_IMG && (attr = gumbo_get_attribute(&node->v.element.attributes, "src"))) {
        GumboAttribute* title = gumbo_get_attribute(&node->v.element.attributes, "title");

        QUrl imageUrl(attr->value);
        QString prettyName(title->value);
        if (!Jcr::Utils::fileExists(imageUrl, Jcr::LOGOROOT, prettyName)) {
            Jcr::ImageDownloader* imageDownloader = new Jcr::ImageDownloader(QUrl(attr->value), Jcr::LOGOROOT, nullptr);
            imageDownloader->setSaveName(prettyName);
            imageDownloader->run();
//            Jcr::Utils::runInThread(imageDownloader);
        }
    }

    GumboVector* children = &node->v.element.children;
    for (auto i = 0; i < children->length; ++i)
        searchForImageLinks(static_cast<GumboNode*>(children->data[i]));
}

void BrandPageParserPrivate::searchForLinksEx(GumboNode* node, const char* name)
{
    if (node->type != GUMBO_NODE_ELEMENT)
        return;

    GumboAttribute* href;
    if (node->v.element.tag == GUMBO_TAG_A && (href = gumbo_get_attribute(&node->v.element.attributes, name))) {
         std::string model = Jcr::GumboUtils::getNodeText(node);
         if (!model.empty()) {
//             qDebug() << "model: " << model.data();
//             std::string brand = Jcr::DatabaseManager::instance()->brandName(QString(model.c_str())).toStdString();
//             if (!brand.empty()) {
                 GumboAttribute* urlAttr = gumbo_get_attribute(&node->v.element.attributes, "href");
                 modelLinkMap.insert(model, std::string(urlAttr->value));
//                 qDebug() << "detail page: " << urlAttr->value;

//                 ModelPageParser* mpp = new ModelPageParser();
//                 mpp->setBrandName(brand.c_str());
//                 mpp->setModelName(model.c_str());
//                 mpp->setUrl(QUrl(urlAttr->value));
//                 mpp->run();
//                 Jcr::Utils::runByThread(mpp);

    //             ::Sleep(5000);

    //             Jcr::Utils::runByThread(mpp);
//             }

         }
    }

    GumboVector* children = &node->v.element.children;
    for (unsigned int i = 0; i < children->length; ++i) {
        searchForLinksEx(static_cast<GumboNode*>(children->data[i]), name);
    }
}

void BrandPageParserPrivate::searchForLinks(GumboNode* node)
{
    if (node->type != GUMBO_NODE_ELEMENT)
        return;

    // clear the pages
    modelDetailPages.clear();
    GumboAttribute* href = nullptr;
    if (node->v.element.tag == GUMBO_TAG_TABLE &&
            (href = gumbo_get_attribute(&node->v.element.attributes, "class")) && strcasecmp(href->value, "t0922_pinpaitab") == 0) {
        GumboVector* children = &node->v.element.children;
        for (unsigned int i = 0; i < children->length; ++i) {
            searchForLinksEx(static_cast<GumboNode*>(children->data[i]), "target");
//            search_for_image_links(static_cast<GumboNode*>(children->data[i]));
        }
    }

    GumboVector* children = &node->v.element.children;
    for (unsigned int i = 0; i < children->length; ++i)
        searchForLinks(static_cast<GumboNode*>(children->data[i]));

}

void BrandPageParserPrivate::searchForBrandModels(GumboNode *node)
{
    if (node->type != GUMBO_NODE_ELEMENT)
        return;

    if (node->v.element.tag == GUMBO_TAG_TR) {
        GumboVector* children = &node->v.element.children;
        int childCount = children->length;
        for (int i = 0; i < childCount; ++i) {
            GumboNode* child = static_cast<GumboNode*>(children->data[i]);
            std::string brandName = Jcr::GumboUtils::getNodeText(child);
            std::vector<std::string> models;
            if (!brandName.empty()) {
                searchForModels(child, models);

                if ((calledTimes++) % 2 == 0) {
                    previousKey = models.at(0);
                    this->brandModelsMap.insert(previousKey, std::vector<std::string>());
                } else {
                    this->brandModelsMap[previousKey] = models;
                }
            }
        }
    }
}

void BrandPageParserPrivate::searchForModels(GumboNode *node, std::vector<std::string>& models)
{
    if (node->type != GUMBO_NODE_ELEMENT)
        return;

    if (node->v.element.tag == GUMBO_TAG_A) {
        GumboAttribute* attr = gumbo_get_attribute(&node->v.element.attributes, "target");
        if (attr && (strncasecmp(attr->value, "_blank") == 0)) {
            std::string model = Jcr::GumboUtils::getNodeText(node);
            if (!model.empty())
                models.push_back(model);
        }
    } else {
        GumboVector* children = &node->v.element.children;
        for (int i = 0; i < children->length; ++i) {
            GumboNode* child = static_cast<GumboNode*>(children->data[i]);
            searchForModels(child, models);
        }
    }
}

/// The home page's functionality is to write brand_name sql table,
BrandPageParser::BrandPageParser(QObject* parent) : AbstractPageParser(parent)
{
    const QString strLogoDir(Jcr::LOGOROOT);
    QDir logoDir(strLogoDir);
    if (!logoDir.exists())
        logoDir.mkdir(strLogoDir);

    setUrl(QUrl(Jcr::BRANDPAGE));
    d_ptr = new BrandPageParserPrivate;
}

BrandPageParser::~BrandPageParser()
{
    delete d_ptr;
}

const StdStringMap& BrandPageParser::modelLinks() const
{
    return d_ptr->modelLinkMap;
}

void BrandPageParser::processNode(GumboNode* node)
{
    d_ptr->searchForLinks(node);
//    d_ptr->searchForBrandModels(node);
}

void BrandPageParser::finalize()
{
//    if (!d_ptr->modelLinkMap.isEmpty())
//        emit getModelLinks(d_ptr->modelLinkMap);
    // print urls
//    foreach (auto url, d_ptr->modelDetailPages)
//        qDebug() << "url: " << url.toString();

    // print brand models
    // already got, disable it
#if 0
    Jcr::DatabaseManager* dbMgr = Jcr::DatabaseManager::instance();
    auto iter = d_ptr->brandModelsMap.begin();
    while (iter != d_ptr->brandModelsMap.end()) {
        std::vector<std::string>& models = iter.value();
        std::string brand = iter.key();
        qDebug() << "brand: " << brand.c_str();
        for (int i = 0; i < models.size(); ++i)
            dbMgr->addBrandModel(QString(brand.c_str()), QString(models.at(i).c_str()));
        ++iter;
    }
#endif
    emit finished();
}

} // namespace jcr
